/**
 * 
 */
package org.pump.client.main;

import java.nio.ByteOrder;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.pump.client.codec.BinlogEvent;
import org.pump.client.codec.InitPack;
import org.pump.client.codec.Packet;
import org.pump.client.codec.PacketBody;
import org.pump.client.codec.PacketHead;
import org.pump.client.codec.ResultPack;
import org.pump.client.codec.TableMapEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author liudong03
 * 
 */
public class MysqlDecoder extends CumulativeProtocolDecoder {
	private static final Logger mylog = LoggerFactory
			.getLogger(MysqlDecoder.class);
	public static final String DECODER_STATE_KEY = "session_message";
	public static final String DECODER_STAGE_KEY = "session_stage";
	public static final String SESSION_PREVIOUS_PACKET = "previous_packet";
	public static final int SERVER_INIT_STAGE = 1;
	public static final int CLIENT_AUTH_STAGE = 2;
	public static final int SERVER_RESPONSE_STAGE = 3;
	public static final int CLIENT_COMMAND_STAGE = 4;
	public static final int SERVER_FORMAT_STAGE = 4;
	public static final int SERVER_DATA_STAGE = 5;
	public static final int SERVER_AUTH_OK = 6;
	public static final int SERVER_AUTH_ERROR = 7;
	public static final int SERVER_DATA_EOF = 7;
	
	
	@Override
	protected boolean doDecode(IoSession session, IoBuffer in,
			ProtocolDecoderOutput out) throws Exception {
		// sessionPacket用于存储解析过程的中间结果
		Packet sessionPacket = (Packet) session.getAttribute(DECODER_STATE_KEY);
		if (sessionPacket == null) {
			sessionPacket = new Packet();
			session.setAttribute(DECODER_STATE_KEY, sessionPacket);
		}
		//prevPacket用于存储TableMapEvent
		Packet prevPacket = (Packet) session.getAttribute(SESSION_PREVIOUS_PACKET);
		if (prevPacket == null) {
			prevPacket = new Packet();
			session.setAttribute(SESSION_PREVIOUS_PACKET, prevPacket);
		}
		//sessionStage用于存储会话所处的阶段
		Integer sessionStage = (Integer) session
				.getAttribute(DECODER_STAGE_KEY);
		if (sessionStage == null) {
			sessionStage = new Integer(MysqlDecoder.SERVER_INIT_STAGE);
			session.setAttribute(DECODER_STAGE_KEY, sessionStage);
		}
		int curstage = sessionStage.intValue();
		//用于设定buffer的字节顺序
		in.order(ByteOrder.LITTLE_ENDIAN);
		//读取包头
		if (sessionPacket.getHead() == null) {
			if(in.remaining() < PacketHead.HEADSIZE)
			{
				mylog.debug("read packet body fail");
				return false;
			}
			PacketHead head = PacketHead.readbuffer(in);
			if (head == null) {
				mylog.error("read packet head fail");
				return false;
			}
			sessionPacket.setHead(head);
		}
		//读取包体
		if (sessionPacket.getBody() == null) {
			PacketBody body = null;
			int bodysize = sessionPacket.getHead().getPacketlen();
			if(in.remaining() < bodysize)
			{
				mylog.debug("read packet body fail");
				return false;
			}
			switch (sessionStage.intValue()) {
			case MysqlDecoder.SERVER_INIT_STAGE:
				//greet_waiting stage
				body = InitPack.readBuffer(in, bodysize);
				if (body == null) {
					mylog.error("read init packet body fail");
					return false;
				}
				Integer nextstage = new Integer(MysqlDecoder.CLIENT_AUTH_STAGE);
				session.setAttribute(MysqlDecoder.DECODER_STAGE_KEY, nextstage);
				mylog.debug("receive init package, the client status is auth_waiting");
				break;
			case MysqlDecoder.CLIENT_AUTH_STAGE:
				//auth_waitting stage
				body = ResultPack.readBuffer(in, bodysize , session, prevPacket, curstage);
				if(body == null){
					mylog.error("read init packet body fail");
					return false;
				}
				break;
			case MysqlDecoder.CLIENT_COMMAND_STAGE:
				body = ResultPack.readBuffer(in, bodysize,session,prevPacket,curstage);
				if(body == null){
					mylog.debug("read data packet body fail");
					return false;
				}
				break;
			}
			sessionPacket.setBody(body);
		} 
		
		PacketHead curhead = sessionPacket.getHead();
		PacketBody curbody = sessionPacket.getBody();
		Packet respack = new Packet(curhead,curbody);
		if(curbody instanceof BinlogEvent)
		{
			if(((BinlogEvent)curbody).getMydata() instanceof TableMapEvent)
			{
				prevPacket.setHead(respack.getHead());
				prevPacket.setBody(respack.getBody());
			}
			else
			{
				mylog.debug("the event is not tablemapevent,mypump won't switch prevpacket");
			}
		}
		
		out.write(respack);

		sessionPacket.setHead(null);
		sessionPacket.setBody(null);
		return true;
	}
}
